/*
 * Copyright 2010 - Jeremie Brebec
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.jb.sharedbills.client.form;

import java.util.ArrayList;
import java.util.List;

import org.jb.sharedbills.client.resources.Resources;
import org.jb.sharedbills.client.stores.BillStore;
import org.jb.sharedbills.client.stores.EventSaver;
import org.jb.sharedbills.client.stores.GroupStore;
import org.jb.sharedbills.client.stores.MemberStore;
import org.jb.sharedbills.client.stores.EventSaver.SaveStateListener;
import org.jb.sharedbills.client.stores.EventSaver.State;
import org.jb.sharedbills.shared.model.Bill;
import org.jb.sharedbills.shared.model.Group;
import org.jb.sharedbills.shared.model.Member;
import org.jb.sharedbills.shared.model.MessageHelper;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.ModelProcessor;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.GridEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Dialog;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.Field;
import com.extjs.gxt.ui.client.widget.form.NumberField;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.grid.CellEditor;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.EditorGrid;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
import com.extjs.gxt.ui.client.widget.grid.GridSelectionModel;
import com.extjs.gxt.ui.client.widget.grid.RowNumberer;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.inject.Inject;

public class BillPanel extends ContentPanel implements SaveStateListener {

	/**
	 * 
	 * @param bills
	 */
	@Inject
	public BillPanel( BillStore billStore, MemberStore memberStore, GroupStore groupStore, EventSaver eventSaver ) {
		
		this.billStore = billStore;
		this.memberStore = memberStore;
		this.groupStore = groupStore;
		this.eventSaver = eventSaver;
		
		setIcon( AbstractImagePrototype.create(Resources.INSTANCE.money()) );
		
		setHeading("Dépenses");
		setHeaderVisible(true);
		setBorders(false);
		setLayout( new FitLayout() );
		
		setTopComponent( createToolbar() );

		eventSaver.addListener(this);
		add( createGrid() );
	}
	
	/**
	 * 
	 * @return
	 */
	private Grid<BeanModel> createGrid() {
		List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
		
		RowNumberer r = new RowNumberer();
		columns.add(r); 
		
		ColumnConfig columnFrom = new ColumnConfig("from","Responsable",150);
		
		ComboBox<BeanModel> comboFrom = new ComboBox<BeanModel>();
		comboFrom.setStore( memberStore );
		comboFrom.setDisplayField("name");
		comboFrom.setAllowBlank(false);
		comboFrom.setEditable(true);
		comboFrom.setForceSelection(false);
		comboFrom.setTriggerAction(TriggerAction.ALL);
		comboFrom.setLazyRender(false);
		columnFrom.setEditor( new TextFieldCellEditor(comboFrom) {
			
			@Override
			public Object postProcessValue(Object value) {
				if (value == null) {
					String raw = getField().getRawValue();
					if (raw == null)
						return null;
					
					Member m = new Member();
					m.setName(raw);
					
					billStore.getEvent().getMembers().add( m );
					
					return MemberStore.memberFactory.createModel(m);
				}
				
				return value;
			}
			
		});
		columnFrom.setRenderer( new GridCellRenderer<BeanModel>() {

			@Override
			public Object render(BeanModel model, String property,
					ColumnData config, int rowIndex, int colIndex,
					ListStore<BeanModel> store, Grid<BeanModel> grid) {
				
				Member m =  model.<Bill>getBean().getFrom();
				return m == null ? null : m.getName();
			}
		});
	    
		ColumnConfig columnTo = new ColumnConfig("to", "Participants", 150);
		ComboBox<BeanModel> comboTo = new ComboBox<BeanModel>();
		comboTo.setStore( groupStore );
		comboTo.setDisplayField("name");
		comboTo.setAllowBlank(false);
		comboTo.setEditable(true);
		comboTo.setTriggerAction(TriggerAction.ALL);
		comboTo.setForceSelection(false);
		comboTo.setLazyRender(false);
		comboTo.setMinListWidth( 250 );
		comboTo.setItemSelector("div.group-item");  
		comboTo.setTemplate(getTemplate());
		comboTo.getListView().setModelProcessor( new ModelProcessor<BeanModel>() {
			
			@Override
			public BeanModel prepareData(BeanModel model) {
				Group g = model.getBean();
				model.set("desc", MessageHelper.format(g.getMembers()));
				return model;
			}
		});
		
		columnTo.setEditor( new TextFieldCellEditor(comboTo) {
			
			@Override
			public Object postProcessValue(Object value) {
				if (value == null) {
					
					String raw = getField().getRawValue();
					if (raw != null) {
						Group g = new Group();
						g.setName( raw );
						
						billStore.getEvent().getGroups().add(g);
						
						GroupDialog dlg = new GroupDialog(billStore.getEvent(), g );
						dlg.show();
						
						return GroupStore.groupFactory.createModel( g );
					}
				}
				
				return value;
			}
			
		});
		columnTo.setRenderer( new GridCellRenderer<BeanModel>() {

			@Override
			public Object render(BeanModel model, String property,
					ColumnData config, int rowIndex, int colIndex,
					ListStore<BeanModel> store, Grid<BeanModel> grid) {
				
				Group g =  model.<Bill>getBean().getTo();
				return g == null ? null : g.getName();
			}
		});
				
		ColumnConfig columnAmount = new ColumnConfig("amount", "Montant", 100 );
		columnAmount.setEditor(new TextFieldCellEditor(new NumberField()));  
		columnAmount.setNumberFormat(NumberFormat.getFormat("0.00"));
		columnAmount.setAlignment(HorizontalAlignment.RIGHT);
		
		ColumnConfig columnDescription = new ColumnConfig("name", "Description", 250 );
		TextField<String> desc = new TextField<String>();  
		desc.setAllowBlank(false);  
		columnDescription.setEditor(new CellEditor(desc)); 
	    
		columns.add(columnFrom);
		columns.add(columnAmount);
		columns.add(columnTo);
		columns.add(columnDescription);
		ColumnModel cm = new ColumnModel(columns);
		
		grid = new EditorGrid<BeanModel>(billStore,cm);
		grid.setSelectionModel( new GridSelectionModel<BeanModel>() );
		grid.addPlugin(r);
		grid.setAutoExpandColumn("name");
		grid.setStripeRows(true);
				
		grid.addListener(Events.BeforeEdit, new Listener<GridEvent<BeanModel>>() {
			@Override
			public void handleEvent(GridEvent<BeanModel> be) {
				if (eventSaver.getState() == State.LOCKED) {
					be.setCancelled(true);
				}
			}
		});
		
		return grid;
	}
	
	/**
	 * 
	 * @return
	 */
	private native String getTemplate() /*-{ 
    return [ 
    '<tpl for="."><div class="group-item" style="font-size: small" >', 
    '<b>{name}</b><br /><i>{desc}</i>', 
    '</div></tpl>' 
    ].join(""); 
  }-*/;  
	
	/**
	 * 
	 * @return
	 */
	private ToolBar createToolbar() {
		ToolBar tb = new ToolBar();
		
		addBtn = new Button("Créer", AbstractImagePrototype.create(Resources.INSTANCE.add()));  
		addBtn.addSelectionListener( new SelectionListener<ButtonEvent>() {
			
			@Override
			public void componentSelected(ButtonEvent ce) {
				Bill b = new Bill();
				b.setTo( billStore.getEvent().getAllMembersGroup() );
				
				grid.stopEditing();
				billStore.getEvent().getBills().add(b);
				grid.startEditing(billStore.getCount() - 1, 1 );
			}
		});
		tb.add( addBtn );
		addBtn.disable();
		
		deleteBtn = new Button("Supprimer", AbstractImagePrototype.create(Resources.INSTANCE.delete()));
		deleteBtn.disable();
		deleteBtn.addSelectionListener( new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				BeanModel m = grid.getSelectionModel().getSelectedItem();
				if (m == null) {
					MessageBox dlg = MessageBox.alert("Suppression", "Aucune ligne sélectionnée" , new Listener<MessageBoxEvent>() {
						@Override
						public void handleEvent(MessageBoxEvent be) {}
					});
					dlg.show();
					return;
				}

				final Bill bill = m.getBean();
				
				MessageBox dlg = MessageBox.confirm("Suppression", "Voulez-vous vraiment supprimer cette dépense ?", new Listener<MessageBoxEvent>() {

					@Override
					public void handleEvent(MessageBoxEvent be) {
						if (Dialog.YES.equals( be.getButtonClicked().getItemId())) {
							groupStore.getEvent().getBills().remove( bill );
						}
					}
				});
				dlg.show();	
			}
		});
		tb.add( deleteBtn );
		
		return tb;
	}
	
	/**
	 * 
	 * @author jeremie
	 *
	 */
	private class TextFieldCellEditor extends CellEditor {

		public TextFieldCellEditor(Field<? extends Object> field) {
			super(field);
		}
		
		@Override
		public void startEdit(Element el, Object value) {
			super.startEdit(el, value);
			
			((TextField<?>)getField()).selectAll();
		}
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.jb.sharedbills.client.stores.EventSaver.SaveStateListener#onStateChange(org.jb.sharedbills.client.stores.EventSaver.State)
	 */
	@Override
	public void onStateChange(State state) {
		if (state == State.COMMIT) {
			billStore.commitChanges();
		} 
		
		if (state != State.LOCKED) {
			addBtn.enable();
			deleteBtn.enable();
		}
	}
	
	final private GroupStore groupStore;
	
	final private MemberStore memberStore;
	
	final private BillStore billStore;
	
	private EditorGrid<BeanModel> grid;
	
	private final EventSaver eventSaver;

	private Button addBtn;
	private Button deleteBtn;



}
